/**
 * jQuery Modular Environment
 * @author 	Dzo dev.dzyu@gmail.com
 * @version 0.1 alpha
 * @description jQuery Modular Environment extension
 */
(function($) {
/*----------------------------------------------------------------------------------------
 * S A N D B O X
 *  ------------------------------------------------------------------------------------ */	
	/**
	 * Sandbox class
	 */
	var Sandbox = function(core) {
		this.$ = $;
		this._core = core;
	};
	/**
	 * Subscribe to the event
	 * @param {string} eventName
	 * @param {function} handler
	 */
	Sandbox.prototype.listen = function(eventName, handler) {
		this._core._bind(eventName, handler);
	};
	/**
	 * Unsubscribe from the event
	 * @param {string} eventName
	 * @param {function} handler
	 */
	Sandbox.prototype.stopListen = function(eventName, handler) {
		this._core._unbind(eventName, handler);
	};
	/**
	 * Provoke the event
	 * @param {string} eventName
	 * @param {object} data
	 */
	Sandbox.prototype.notify = function(eventName, data) {
		this._core._trigger(eventName, data);
	};
	
/*----------------------------------------------------------------------------------------
 * M O D U L E
 *  ------------------------------------------------------------------------------------ */	
	/**
	 * @param {function} creator
	 */
	var Module = function(creator) {
		this.creator 	= creator;
		this.instance 	= null;
		this.started	= false;
	};
	
/*----------------------------------------------------------------------------------------
 * C O R E
 *  ------------------------------------------------------------------------------------ */	
	/**
	 * The modular Core
	 */
	var Core = (function(undifened) {
		var modules 		= {}; 	// Set of modules
		var modulesCount 	= 0;	// How many modules was registered
		var debug 			= true;	// Turn on/off debug mode
		
		// Some utility methods
		var Util = {
			isString: function(string) {return typeof string === 'string';},
			isArray: function(array) {return $.isArray(array);},
			isFunction: function(func) {return $.isFunction(func);}
		};
		
		// Event manager for bind and trigger handlers
		var eventManager = $('<a/>');
		
		return {
			/*----------------------------------------------------------------------------------------
			 * L O G G I N G
			 *  ------------------------------------------------------------------------------------ */	
			/** Logging object */
			_log : {
				info: function() {
					if(debug) {
						console.log.apply(window.console, arguments);
					}
				},
				warn: function() {
					if(debug) {
						console.warn.apply(window.console, arguments);						
					}
				},
				error: function() {
					if(debug) {
						console.error.apply(window.console, arguments);						
					}
				}
			},
			
			/*----------------------------------------------------------------------------------------
			 * B I N D I N G
			 *  ------------------------------------------------------------------------------------ */	
			/**
			 * Add a handler for an event
			 * @param {string} eventName Event name
			 * @param {function} handler
			 */
			_bind: function(eventName, handler) {
				eventManager.bind(eventName, handler);
			},
			
			/**
			 * Provoke an event
			 * @param {string} eventName Event name
			 * @param {object} data
			 */
			_trigger: function(eventName, data) {
				eventManager.trigger(eventName, [data]);
			},
			
			/**
			 * Remove a handler
			 * @param {string} eventName Event name
			 * @param {function} handler
			 */
			_unbind: function(eventName, handler) {
				eventManager.unbind(eventName, handler);
			},

			/*----------------------------------------------------------------------------------------
			 * S A N D B O X   P R O T O T Y P E   E X T E N D
			 *  ------------------------------------------------------------------------------------ */	
			extendSandbox: function(extendArg) {
				for(var x in extendArg) {
					if(extendArg[x] === null) {
						delete Sandbox.prototype[x];
					} else {
						Sandbox.prototype[x] = extendArg[x];						
					}
				}
				this._log.info(Sandbox.prototype);
			},
			
			/*----------------------------------------------------------------------------------------
			 * M A N A G A M E N T
			 *  ------------------------------------------------------------------------------------ */	
			/**
			 * Register module in the Core
			 * @param {string} moduleId
			 * @param {function} creator
			 */
			register: function(moduleId, creator) {
				if(!modules[moduleId] && Util.isString(moduleId) && Util.isFunction(creator)) {
					modules[moduleId] = new Module(creator);
					
					this._log.info("Module \"" + moduleId + "\" succesfull registered");
				} else {
					this._log.warn("Module \"" + moduleId + "\" register failed. Some parameters are not valid type or module with same id already registered");
				}
			},
			
			/**
			 * Unregister the module
			 * @param {string} moduleId
			 */
			unregister: function(moduleId) {
				if(modules[moduleId]){
					this.stop(moduleId);
					delete modules[moduleId];

					this._log.info("Module \"" + moduleId + "\" succesfull unregistered");
				} else {
					this._log.warn("Module \"" + moduleId + "\" cannot be unregistered. Maybe it's not exists");
				}
			},
			
			/**
			 * Start the module by id
			 * @param {string} moduleId
			 */
			start: function(moduleId) {
				if(modules[moduleId] && !modules[moduleId].started) {
					
					/* Run module creator */
					modules[moduleId].instance = modules[moduleId].creator(new Sandbox(this));
					
					/* If a creator returns no value, module has no sense for life */
					if(!modules[moduleId].instance) {
						this._log.error("Module \"" + moduleId + "\" can not to start. It has a not valid creator. Module has no sense for life. It was unregistered");
						this.unregister(moduleId);
						return;
					}
					
					/* Run module init method if exists */
					if(modules[moduleId].instance && modules[moduleId].instance['init']) {
						modules[moduleId].instance.init();
					}
					
					modules[moduleId].started = true;
					modulesCount++;
					
					this._log.info("Module \"" + moduleId + "\" succesfull started");
				} else {
					this._log.error("Module \"" + moduleId + "\" can not to start. May be it's started already");					
				}
			},
			
			/**
			 * Stop the module by id
			 * @param {string} moduleId
			 */
			stop: function(moduleId) {
				if(modules[moduleId] && modules[moduleId].started) {
					
					/* Run module destroy method if exists */
					if(modules[moduleId].instance && modules[moduleId].instance['destroy']) {
						modules[moduleId].instance.destroy();
					}
					
					/* Run module destroyer */
					modules[moduleId].instance = null;
					
					modules[moduleId].started = false;
					modulesCount--;
					
					this._log.info("Module \"" + moduleId + "\" succesfull stoped");
				}
				else {
					this._log.error("Module \"" + moduleId + "\" can not to stop. May be it doesn't started or doesn't registered");
				}
			},
			
			/**
			 * Start all registered modules
			 */
			startAll: function() {
				for(var moduleId in modules) {
					this.start(moduleId);
				};
			},
			
			/**
			 * Stop all registered modules
			 */
			stopAll: function() {
				for(var moduleId in modules) {
					this.stop(moduleId);
				};				
			},
		};
		
	}());
	
	
	$.Module = Core;
	
}(jQuery));